#include "webrtc.hpp"
#include <random>

using namespace std;
using json = nlohmann::json;
WebRTC::WebRTC()
{
    // localId_ = randomId(4);
    cout << "localId: " << localId_ << endl;
}
WebRTC::~WebRTC()
{
    delete ws_;
}
rtc::PeerConnection *WebRTC::createPeerConnection(string id, Dart_Port port)
{
    rtc::Configuration config;
    auto pc = new rtc::PeerConnection(config);
    pc->onTrack([](std::shared_ptr<rtc::Track> track) -> void
                {
			std::cout << "Track received" << std::endl; 
			
			cout << "Track mid: " << track->mid() << endl; 
			cout << "==============================" << endl; });
    pc->onStateChange(
        [](rtc::PeerConnection::State state)
        { std::cout << "State: " << state << std::endl; });

    pc->onGatheringStateChange([](rtc::PeerConnection::GatheringState state)
                               { std::cout << "Gathering State: " << state << std::endl; });
    // 需要与websocket通信 的就需要给websocket传递消息，由于是异步的，需要阻塞
    pc->onLocalDescription([this, id](rtc::Description description)
                           {
		json message = {
		    {"id", id}, {"type", description.typeString()}, {"sdp", std::string(description)}};
        ws_->send(message.dump()); });

    pc->onLocalCandidate([this, id](rtc::Candidate candidate)
                         {
		json message = {{"id", id},
		                {"type", "candidate"},
		                {"candidate", std::string(candidate)},
		                {"mid", candidate.mid()}};

			ws_->send(message.dump()); });
    auto fun = std::bind(&WebRTC::onDataChannel_, this, placeholders::_1, id, port);
    pc->onDataChannel(fun);

    // dataChannelsMap_.emplace(id, pc);
    pcDartPortMap_.emplace(pc, new DartPort(port));
    return pc;
}

void WebRTC::onDataChannel_(shared_ptr<rtc::DataChannel> dc, string id, Dart_Port port)
{
    std::cout << "DataChannel from " << id << " received with label \"" << dc->label() << "\""
              << std::endl;
    std::cout << "DataChannel from " << id << " received with label \"" << dc->label() << "\""
              << std::endl;

    dc->onOpen([this, wdc = make_weak_ptr(dc)]()
               {
			if (auto dc = wdc.lock())
				dc->send("Hello from " + localId_); 
    });

    dc->onClosed([id]()
                 { std::cout << "DataChannel from " << id << " closed" << std::endl; });

    dc->onMessage([id](auto data)
                  {
			// data holds either std::string or rtc::binary
			if (std::holds_alternative<std::string>(data)) {
				std::cout << "Message from " << id << " received: " << std::get<std::string>(data)
				          << std::endl;
                
            }
			else
				std::cout << "Binary message from " << id
				          << " received, size=" << std::get<rtc::binary>(data).size() << std::endl; 

    });

    // peerConnectionsMap_.emplace(id, dc);
    dcDartPortMap_.emplace(dc.get(), new DartPort(port));
}

// std::string randomId(size_t length)
// {
//     using std::chrono::high_resolution_clock;
//     static thread_local std::mt19937 rng(
//         static_cast<unsigned int>(high_resolution_clock::now().time_since_epoch().count()));
//     static const std::string characters(
//         "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
//     std::string id(length, '0');
//     std::uniform_int_distribution<int> uniform(0, int(characters.size() - 1));
//     std::generate(id.begin(), id.end(), [&]()
//                   { return characters.at(uniform(rng)); });
//     return id;
// }
